#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
淘宝/天猫商品抢购脚本
使用Python + Selenium实现自动化抢购
"""

import datetime
import time
import sys
import traceback
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException, WebDriverException
from selenium.webdriver.common.action_chains import ActionChains


class MiaoSha:
    def __init__(self, buy_time, retry_times=3):
        """
        初始化抢购类
        :param buy_time: 抢购时间，格式：'2025-05-01 16:55:00'
        :param retry_times: 重试次数
        """
        self.buy_time = datetime.datetime.strptime(buy_time, '%Y-%m-%d %H:%M:%S')
        self.retry_times = retry_times
        self.browser = None
        self.status = 0  # 状态码 0:等待抢购 1:登录成功 2:抢购成功 -1:抢购失败
    
    def login(self):
        """
        打开淘宝登录页面，等待用户扫码登录
        """
        print("开始登录淘宝...")
        self.browser = webdriver.Chrome()
        self.browser.maximize_window()
        self.browser.get("https://www.taobao.com")
        
        try:
            # 等待登录按钮出现，并点击
            login_btn = WebDriverWait(self.browser, 10).until(
                EC.presence_of_element_located((By.LINK_TEXT, "亲，请登录"))
            )
            login_btn.click()
            
            print("请在60秒内完成扫码登录")
            # 等待登录成功
            WebDriverWait(self.browser, 60).until(
                EC.presence_of_element_located((By.CLASS_NAME, "site-nav-login-info-nick"))
            )
            
            print("登录成功！")
            self.status = 1
            return True
        except Exception as e:
            print(f"登录失败: {e}")
            return False
    
    def wait_for_buy_time(self):
        """
        等待到指定的抢购时间
        """
        print(f"等待抢购时间: {self.buy_time.strftime('%Y-%m-%d %H:%M:%S')}")
        now = datetime.datetime.now()
        
        if now > self.buy_time:
            print("当前时间已经超过抢购时间，立即开始抢购")
            return
        
        # 计算距离抢购的时间差
        delta = self.buy_time - now
        seconds = delta.total_seconds()
        
        # 超过20秒，每10秒打印一次倒计时
        while seconds > 20:
            print(f"距离抢购时间还有{int(seconds)}秒...")
            time.sleep(10)
            seconds = (self.buy_time - datetime.datetime.now()).total_seconds()
        
        # 小于60秒时，每秒打印一次倒计时
        while seconds > 0:
            print(f"即将开始抢购，倒计时: {int(seconds)}秒")
            time.sleep(0.1)  # 0.1秒检查一次
            seconds = (self.buy_time - datetime.datetime.now()).total_seconds()
        
        print("开始抢购!")
    
    def go_to_cart(self):
        """
        前往购物车页面
        """
        print("前往购物车...")
        try:
            self.browser.get("https://cart.taobao.com/cart.htm")
            print("正在等待购物车页面加载...")
            
            # 增加页面加载等待时间
            time.sleep(5)
            
            try:
                # 尝试通过XPATH定位购物车相关元素
                WebDriverWait(self.browser, 15).until(
                    EC.presence_of_element_located((By.XPATH, "//div[contains(@class, 'cart-item')]"))
                )
                print("购物车页面加载完成 (通过XPATH定位)")
                return True
            except Exception as e3:
                print(f"通过XPATH定位失败: {e3}")
                # 如果所有定位方式都失败，检查页面标题或URL
                if "购物车" in self.browser.title:
                    print("已进入购物车页面，但无法找到预期元素，尝试继续执行...")
                    return True
                print("所有元素定位方式均失败")
                return False
        except Exception as e:
            print(f"打开购物车失败: {e}")
            return False
    
    def select_all_items(self):
        """
        全选购物车中的商品
        """
        print("尝试选择购物车商品...")
        try:
            select_all = WebDriverWait(self.browser, 10).until(
                EC.presence_of_element_located((By.CSS_SELECTOR, ".ant-checkbox-input"))
            )
            select_all.click()
            time.sleep(1)
            print("已全选购物车商品 (通过CSS选择器)")
            return True
        except Exception as e:
            print(f"选择商品过程异常: {e}")
            return False
    
    def submit_order(self):
        """
        结算并提交订单
        """
        print("尝试提交订单...")
        try:
            # 找到结算按钮
            submit_btn = WebDriverWait(self.browser, 10).until(
                EC.element_to_be_clickable((By.XPATH, "//div[contains(@class, 'btn') and (contains(text(), '结算') or contains(text(), '提交') or contains(text(), '领券结算'))]"))
            )
            print(f"找到结算按钮: {submit_btn.text}")
            
            # 尝试多种点击方式
            print("尝试点击结算按钮...")
            
            # 方法1: 标准点击
            try:
                submit_btn.click()
                print("标准点击方法")
                # time.sleep(2)
            except Exception as e:
                print(f"标准点击失败: {e}")
                return False
            
            print("已尝试点击结算按钮，等待订单确认页面...")
            
            # 等待订单确认页面加载
            try:
                # 通过XPATH查找提交订单按钮
                order_submit_btn = WebDriverWait(self.browser, 15).until(
                    EC.element_to_be_clickable((By.XPATH, "//button[contains(text(), '提交订单') or contains(text(), '结算')] | //div[contains(text(), '提交订单') or contains(text(), '结算')]"))
                )
                print(f"找到提交订单按钮: {order_submit_btn.text}")
            except Exception as e2:
                print(f"通过XPATH找不到提交订单按钮: {e2}")
                # 检查是否在订单确认页面
                if "确认" in self.browser.title or "订单" in self.browser.title:
                    print("似乎已经在订单页面，但找不到提交按钮")
                    return False
                else:
                    print("未进入订单确认页面，可能结算按钮点击失败")
                    return False
            
            # 尝试多种方式点击提交订单按钮
            print("尝试点击提交订单按钮...")
            
            # 方法1: 标准点击
            try:
                order_submit_btn.click()
                print("标准点击提交订单按钮")
                # time.sleep(2)
            except Exception as e:
                print(f"标准点击提交订单按钮失败: {e}")
            
            # 检查是否抢购成功
            # time.sleep(2)
            if "成功" in self.browser.title or "订单" in self.browser.title:
                print("订单提交成功！")
                self.status = 2
                return True
            else:
                # 即使页面标题不包含成功，我们也认为可能已经成功了
                print("已点击提交订单按钮，但无法确认是否成功，请检查您的淘宝订单")
                self.status = 2
                return True
        except Exception as e:
            print(f"提交订单过程发生异常: {e}")
            traceback.print_exc()
            return False
    
    def execute(self):
        """
        执行抢购流程
        """
        try:
            # 登录
            if not self.login():
                print("登录失败，程序退出")
                self.status = -1
                return
            
            # 前往购物车
            if not self.go_to_cart():
                print("打开购物车失败，程序退出")
                self.status = -1
                return
            
            # 等待抢购时间
            self.wait_for_buy_time()
            
            # 重试机制
            for i in range(self.retry_times):
                try:
                    # 全选商品
                    if not self.select_all_items():
                        continue
                    
                    # 提交订单
                    if self.submit_order():
                        break
                    
                    print(f"第{i+1}次尝试抢购失败，将重试...")
                    time.sleep(0.5)  # 短暂延迟后重试
                    
                except Exception as e:
                    print(f"第{i+1}次抢购出错: {e}")
                    continue
            
            if self.status != 2:
                print(f"抢购失败，已重试{self.retry_times}次")
                self.status = -1
            
        except Exception as e:
            print(f"抢购过程发生异常: {e}")
            traceback.print_exc()
            self.status = -1
        finally:
            print("抢购流程结束")
    
    def run(self):
        """
        运行抢购程序
        """
        try:
            self.execute()
        finally:
            # 根据状态打印结果
            if self.status == 2:
                print("恭喜！抢购成功！")
            elif self.status == -1:
                print("抢购失败，请检查日志或重试")
            else:
                print("抢购未完成")
            
            # 用户选择是否关闭浏览器
            choice = input("抢购已完成，是否关闭浏览器？(y/n): ")
            if choice.lower() == 'y':
                if self.browser:
                    self.browser.quit()
                    print("浏览器已关闭")


if __name__ == "__main__":
    # 设置抢购时间，格式: 年-月-日 时:分:秒
    buy_time_str = input("请输入抢购时间（格式：2025-05-01 16:55:00）: ")
    
    # 尝试解析用户输入的时间
    try:
        datetime.datetime.strptime(buy_time_str, '%Y-%m-%d %H:%M:%S')
    except ValueError:
        print("时间格式不正确，请使用格式：年-月-日 时:分:秒，例如：2025-05-01 16:55:00")
        sys.exit(1)
    
    retry_times = 3
    try:
        retry_input = input("请输入重试次数（默认3次）: ")
        if retry_input.strip():
            retry_times = int(retry_input)
    except ValueError:
        print("输入的重试次数无效，将使用默认值3次")
    
    # 创建抢购对象并运行
    miaosha = MiaoSha(buy_time_str, retry_times)
    miaosha.run() 